En esta práctica se elabora un caso práctico orientado a aprender a identificar los datos relevantes para un proyecto analítico y usar las herramientas de integración, limpieza, validación y análisis de los mismos.
● Aprender a aplicar los conocimientos adquiridos y su capacidad de resolución de problemas en entornos nuevos o poco conocidos dentro de contextos más amplios o multidisciplinares.
● Saber identificar los datos relevantes y los tratamientos necesarios (integración, limpieza y validación) para llevar a cabo un proyecto analítico.
● Aprender a analizar los datos adecuadamente para abordar la información contenida en los datos.
● Identificar la mejor representación de los resultados para aportar conclusiones sobre el problema planteado en el proceso analítico.
● Actuar con los principios éticos y legales relacionados con la manipulación de datos en función del ámbito de aplicación.
● Desarrollar las habilidades de aprendizaje que les permitan continuar estudiando de un modo que tendrá que ser en gran medida autodirigido o autónomo.
● Desarrollar la capacidad de búsqueda, gestión y uso de información y recursos en el ámbito de la ciencia de datos.
A continuación, realizamos la descripción de las variables que hay en el dataset “Heart Attack Analysis & Prediction dataset”, usando la información encontrada en la web [Kaggle datasets] (https://www.kaggle.com/datasets), concretamente en el siguiente enlace: https://www.kaggle.com/datasets/rashikrahmanpritom/heart-attack-analysis-prediction-dataset
** Características de las variales incluidas:**
age: Edad del paciente
sex : Sexo del paciente (F=0; M=1)
cp : Tipo dolor torácico
Value 1 : Angina típica (TA)
Value 2 : Angina atípica (ATA)
Value 3 : Dolor no-anginal (NAP)
Value 4 : Asintomático (ASY)
trtbps : Presión arterial en reposo (in mm Hg)
chol : Colesterol en mg/dl obtenido a través del sensor de IMC
fbs : (Glucemia en ayunas > 120 mg/dl) (1 = true; 0 = false)
restecg : Resultados del electrocardiograma en reposo
Value 0 : Normal
Value 1 : Presentar anomalías de la onda ST-T (inversión de la onda T y/o elevación o depresión del ST de > 0,05 mV)
Value 2 : Hipertrofia ventricular izquierda probable o definida según los criterios de Estes
thalachh : Frecuencia cardiaca máxima alcanzada
exng : Angina inducida por esfuerzo (1 = yes; 0 = no)
oldpeak : Pico previo
slp : Pendiente del segmento ST máximo del ejercicio
caa : Número de buques principales (0-3)
thall : Tasa de mortalidad
output : 0= menor probabilidad de infarto 1= mayor probabilidad de infarto
Primero de todo, cargamos las librerías que vamos a usar durante la práctica
if (!require('dplyr')) install.packages('dplyr');library(dplyr)
if (!require('ggplot2')) install.packages('ggplot2');library(ggplot2)
if (!require('reshape')) install.packages('reshape');library(reshape)
if (!require('plotly')) install.packages('plotly');library(plotly)
if (!require('plyr')) install.packages('plyr');library(plyr)
if (!require('Stat2Data')) install.packages('Stat2Data');library(Stat2Data)
if (!require('corrplot')) install.packages('corrplot');library(corrplot)
if (!require('Matrix')) install.packages('matrix');library(Matrix)
if (!require('patchwork')) install.packages('patchwork');library(patchwork)
if (!require('ggcorrplot')) install.packages('ggcorrplot');library(ggcorrplot)
if (!require('corrplot')) install.packages('ggcorrplot');library(corrplot)
if (!require('DataExplorer'))install.packages('DataExplorer');library(DataExplorer)
if (!require('psych'))install.packages('psych');library(psych)
if (!require('highcharter'))install.packages('highcharter');library(highcharter)
if (!require('tidyverse'))install.packages('tidyverse');library(tidyverse)
if (!require('GGally'))install.packages('GGally');library(GGally)
if (!require('htmltools'))install.packages('htmltools');library(htmltools)
# setwd
dir <- dirname(rstudioapi::getSourceEditorContext()$path)
setwd(dir)
Cargamos los datos de la base de datos “heart” y tipificamos las variables que tiene el conjunto de datos como corresponde
library(readxl)
heart <- read_excel("heart.xlsx")
# Mostramos los primeros registros del conjunto de dtos, con el fin de ver una aproximación de como es el conjunto y su estructura
head(heart, max(10))
## # A tibble: 10 × 14
## age sex cp trtbps chol fbs restecg thalachh exng oldpeak slp
## <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
## 1 63 1 3 145 233 1 0 150 0 2.3 0
## 2 37 1 2 130 250 0 1 187 0 3.5 0
## 3 41 0 1 130 204 0 0 172 0 1.4 2
## 4 56 1 1 120 236 0 1 178 0 0.8 2
## 5 57 0 0 120 354 0 1 163 1 0.6 2
## 6 57 1 0 140 192 0 1 148 0 0.4 1
## 7 56 0 1 140 294 0 0 153 0 1.3 1
## 8 44 1 1 120 263 0 1 173 0 0 2
## 9 52 1 2 172 199 1 1 162 0 0.5 2
## 10 57 1 2 150 168 0 1 174 0 1.6 2
## # ℹ 3 more variables: caa <dbl>, thall <dbl>, output <dbl>
str(heart)
## tibble [303 × 14] (S3: tbl_df/tbl/data.frame)
## $ age : num [1:303] 63 37 41 56 57 57 56 44 52 57 ...
## $ sex : num [1:303] 1 1 0 1 0 1 0 1 1 1 ...
## $ cp : num [1:303] 3 2 1 1 0 0 1 1 2 2 ...
## $ trtbps : num [1:303] 145 130 130 120 120 140 140 120 172 150 ...
## $ chol : num [1:303] 233 250 204 236 354 192 294 263 199 168 ...
## $ fbs : num [1:303] 1 0 0 0 0 0 0 0 1 0 ...
## $ restecg : num [1:303] 0 1 0 1 1 1 0 1 1 1 ...
## $ thalachh: num [1:303] 150 187 172 178 163 148 153 173 162 174 ...
## $ exng : num [1:303] 0 0 0 0 1 0 0 0 0 0 ...
## $ oldpeak : num [1:303] 2.3 3.5 1.4 0.8 0.6 0.4 1.3 0 0.5 1.6 ...
## $ slp : num [1:303] 0 0 2 2 2 1 1 2 2 2 ...
## $ caa : num [1:303] 0 0 0 0 0 0 0 0 0 0 ...
## $ thall : num [1:303] 1 2 2 2 2 1 2 3 3 2 ...
## $ output : num [1:303] 1 1 1 1 1 1 1 1 1 1 ...
El conjunto de datos consiste en 14 variables numéricas (columnas continuas).
library(dplyr)
# Clasificamos las variables en numéricas o en categóricas
# Numéricas
heart <- heart%>%
mutate_at(vars(age,trtbps,chol, thalachh, oldpeak), as.numeric)
# Categóricas
heart <- heart%>%
mutate_at(vars(sex, cp, fbs, restecg, exng, slp, thall, caa, output), as.character)
# Observamos las dimensiones del dataset "heart"
heart.cols<-dim(heart)[2]
heart.rows<-dim(heart)[1]
# Obtenemos un primer vistazo estadístico de cada atirbuto
describeBy(heart)
## Warning in describeBy(heart): no grouping variable requested
## vars n mean sd median trimmed mad min max range skew
## age 1 303 54.37 9.08 55.0 54.54 10.38 29 77.0 48.0 -0.20
## sex* 2 303 1.68 0.47 2.0 1.73 0.00 1 2.0 1.0 -0.78
## cp* 3 303 1.97 1.03 2.0 1.86 1.48 1 4.0 3.0 0.48
## trtbps 4 303 131.62 17.54 130.0 130.44 14.83 94 200.0 106.0 0.71
## chol 5 303 246.26 51.83 240.0 243.49 47.44 126 564.0 438.0 1.13
## fbs* 6 303 1.15 0.36 1.0 1.06 0.00 1 2.0 1.0 1.97
## restecg* 7 303 1.53 0.53 2.0 1.52 0.00 1 3.0 2.0 0.16
## thalachh 8 303 149.65 22.91 153.0 150.98 22.24 71 202.0 131.0 -0.53
## exng* 9 303 1.33 0.47 1.0 1.28 0.00 1 2.0 1.0 0.74
## oldpeak 10 303 1.04 1.16 0.8 0.86 1.19 0 6.2 6.2 1.26
## slp* 11 303 2.40 0.62 2.0 2.46 1.48 1 3.0 2.0 -0.50
## caa* 12 303 1.73 1.02 1.0 1.54 0.00 1 5.0 4.0 1.30
## thall* 13 303 3.31 0.61 3.0 3.36 0.00 1 4.0 3.0 -0.47
## output* 14 303 1.54 0.50 2.0 1.56 0.00 1 2.0 1.0 -0.18
## kurtosis se
## age -0.57 0.52
## sex* -1.39 0.03
## cp* -1.21 0.06
## trtbps 0.87 1.01
## chol 4.36 2.98
## fbs* 1.88 0.02
## restecg* -1.37 0.03
## thalachh -0.10 1.32
## exng* -1.46 0.03
## oldpeak 1.50 0.07
## slp* -0.65 0.04
## caa* 0.78 0.06
## thall* 0.25 0.04
## output* -1.97 0.03
Con la librería DataExplorer vemos una vista general del conjunto de datos de análisis una vez seleccionados, basandonos en los valores faltantes, columnas discretas y continuas.
library(DataExplorer)
plot_intro(heart, title = "Información Dataset")
introduce(heart)
## # A tibble: 1 × 9
## rows columns discrete_columns continuous_columns all_missing_columns
## <int> <int> <int> <int> <int>
## 1 303 14 9 5 0
## # ℹ 4 more variables: total_missing_values <int>, complete_rows <int>,
## # total_observations <int>, memory_usage <dbl>
Según la tabla y el barplot creado, podemos ver como el conjunto de datos heart tiene 14 atributos y 303 observaciones, el cual contiene un total de 9 columnas discretas y 5 columnas continuas. Observamos como no hay valores faltantes.
Ahora vamos a visualizar la información básica del conjunto de datos en función de la variable ‘output’ de interés
# La variable output nos va indicar quien tiene o no una mayor probabilidad de sufrir un ataque al corazón, por lo que primero calculamos el porcentaje de pacientes que tienen mayor probabilidad y luego el resto
print("Porcentaje de personas con probabilidad de infarto")
## [1] "Porcentaje de personas con probabilidad de infarto"
round((sum(heart$output == 1)/nrow(heart)) * 100, 2)
## [1] 54.46
print("Porcentaje de personas sin probabilidad de infarto")
## [1] "Porcentaje de personas sin probabilidad de infarto"
round((sum(heart$output == 0)/nrow(heart))*100,2)
## [1] 45.54
# Convirtimos todas las variables a numéricas (asegúrate de que las variables sean numéricas)
heart_numeric <- sapply(heart, as.numeric)
# Calculamos la matriz de correlación
correlation_tab <- cor(heart_numeric)
library(RColorBrewer)
# Definimos una nueva paleta de colores
new_col <- colorRampPalette(c("#0000CD", "#7D26CD", "#FFFFFF","#FF6347","#FF0000"))
# Creamos la matriz de correlación con corrplot y personalización adicional
corrplot(correlation_tab,
method = "color",
tl.col = "black",
tl.srt = 45,
tl.cex = 0.8,
cl.cex = 0.8,
col = new_col(200),
addCoef.col = "black",
order = "AOE",
number.cex = 0.8,
title = "Matriz de Correlación")
# Valores duplicados
get_duplicates <- function(heart){
total_rows = dim(heart)[1]
unique_rows = dim(heart %>% group_by_all %>% count)[1]
n_duplicates = (total_rows - unique_rows)
cat('n duplicates -> ', n_duplicates)
}
get_duplicates(heart) # Vemos que hay un valor duplicado
## n duplicates -> 1
heart = unique(heart)
cat('Eliminamos la fila duplicada')
## Eliminamos la fila duplicada
get_duplicates(heart)
## n duplicates -> 0
Ya no tenemos valores duplicados en el conjunto de datos
Primero discretizaremos las variables categóricas, asignando a cada valor la correspondiente definición de la variable
# Hacemos cópia del conjunto para usarlo solamente en este análisis:
heart_discr<-heart
# Sexo del paciente (sex)
heart_discr$sex <- ifelse(heart_discr$sex == 0, "Mujer", "Hombre")
# Dolor Torácico (cp)
heart_discr$cp <- factor(heart_discr$cp, levels = c(1, 2, 3, 4), labels = c("Angina Típica", "Angina Atípica", "No Anginal", "Asintomático"))
# Resultados del Electrocardiograma en Reposo (restecg)
heart_discr$restecg <- factor(heart_discr$restecg, levels = c(0, 1, 2), labels = c("Normal", "Anomalías ST-T", "Hipertrofia ventricular"))
# Angina Inducida por Esfuerzo (exng)
heart_discr$exng <- ifelse(heart_discr$exng == 1, "Si", "No")
# Número de Buques Principales (caa) (0-3)
heart_discr$caa <- as.character(heart_discr$caa)
# Glucemia en Ayunas (fbs)
heart_discr$fbs <- ifelse(heart_discr$fbs == 1, "Verdadero", "Falso")
# Pendiente del Segmento ST Máximo del Ejercicio (slp)
heart_discr$slp <- factor(heart_discr$slp, levels = c(0, 1, 2), labels = c("Tipo 0", "Tipo 1", "Tipo 2"))
# Tasa de Mortalidad (thall)
heart_discr$thall <- factor(heart_discr$thall, levels = c(0, 1, 2, 3), labels = c("Thal0", "Thal1", "Thal2", "Thal3"))
# Ouput/Target (0= menor probabilidad de infarto 1= mayor probabilidad de infarto)
heart_discr$output <- factor(heart_discr$output, levels = c(0, 1), labels = c("Menor probabilidad", "Mayor probabilidad"))
A continuación estudiamos la estadística básica de las variables categóricas del conjunto heart
library(dplyr)
library(ggplot2)
par(mfrow = c(2, 2))
categorical_var <- list("sex", "cp", "fbs", "restecg", "exng", "slp", "caa", "thall")
for (i in categorical_var) {
plot_data <- as.data.frame(table(heart_discr[[i]], heart_discr$output))
colnames(plot_data) <- c(i, "output", "Freq")
plot <- ggplot(plot_data, aes_string(x = i, y = "Freq", fill = "output")) +
geom_bar(stat = "identity", position = position_dodge()) +
scale_fill_manual(values = c("#BA55D3", "#6699CC"),
name = "Probabilidad de Infarto",
labels = c('0-Menor', '1-Mayor')) +
labs(x = i, y = "Número de Observaciones") +
theme_minimal() + # Cambio de tema a minimal
theme(panel.background = element_rect(fill = "white"), # Fondo blanco
axis.line = element_line(color = "black")) # Líneas de ejes negras
print(plot)
}
## Warning: `aes_string()` was deprecated in ggplot2 3.0.0.
## ℹ Please use tidy evaluation idioms with `aes()`.
## ℹ See also `vignette("ggplot2-in-packages")` for more information.
## This warning is displayed once every 8 hours.
## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
## generated.
Observaciones
Según el thall, el riesgo de infarto se alcanza en las personas con frecuencia cardíaca máxima(clase 2). En la característica sexo, la clase 1 tiene más posibilidades de sufrir un infarto que la clase 0. Las probabilidades de sufrir un infarto son mayores en la clase 0 de sexo. Comparando con el análisis de correlación, la característica fbs muestra la menor correlación con la salida. En caa, las personas con clase, son más propensas a sufrir un ataque al corazón que las personas con clase 4, 3 y 2. Según la característica cp, las personas con dolor no anginoso tienen más probabilidades de sufrir un infarto que las personas con dolor anginoso atípico y típico. En exng, las personas con clase 1 tienen altas probabilidades de riesgo de infarto, mientras que las personas con clase 0 son menos propensas al infarto. La característica Slp muestra que la clase 0 tiene menos correlación con el resultado que las clases 1 y 2.
A continuación estudiamos la estadística básica de las variables numéricas del conjunto
# Creamos un gráfico de pares con las variables numéricas del conjunto de datos "heart"
# Establecer opciones para el tamaño del gráfico
options(repr.plot.width = 20, repr.plot.height = 20)
# Creamos un gráfico de pares con las variables numéricas del conjunto de datos "heart"
pair_plot <- ggpairs(heart, columns = c("age", "trtbps", "chol", "thalachh", "oldpeak"),
aes(color = as.factor(output), alpha = 0.5),
lower = list(continuous = "smooth"),
palette = c('blue', 'red')) + # Usamos la misma paleta de colores
theme_bw() +
theme(text = element_text(size = 8),
panel.grid = element_blank(),
legend.position = "right",
legend.title = element_text(face = "bold")) +
ggtitle("Variables Numéricas") +
labs(color = "Output", alpha = "Transparencia")
## Warning in warn_if_args_exist(list(...)): Extra arguments: 'palette' are being
## ignored. If these are meant to be aesthetics, submit them using the 'mapping'
## variable within ggpairs with ggplot2::aes or ggplot2::aes_string.
pair_plot
# Convertimos el gráfico a un gráfico interactivo con plotly
interactive_plot <- ggplotly(pair_plot)
## Warning: Can only have one: highlight
## Warning: Can only have one: highlight
## Warning: Can only have one: highlight
## Warning: Can only have one: highlight
# Mostramos el gráfico interactivo
interactive_plot
Seguidamente es importante estudiar la posibilidad de valores outliers para las variables numéricas de la base de datos
# Cargamos librerías necesarias
library(ggplot2)
# Reorganizamos el dataframe para plotear las variables seleccionadas
selected_vars <- heart[, c("age", "oldpeak", "chol", "thalachh", "trtbps")]
selected_vars <- stack(selected_vars)
# Agregamos la columna 'output' al dataframe para usarla en el color de los puntos
selected_vars$output <- heart$output
# Creamos un gráfico de cajas con puntos superpuestos para las variables numéricas seleccionadas
ggplot(selected_vars, aes(x = ind, y = values, color = as.factor(output))) +
geom_boxplot(alpha = 0.7, outlier.size = 2) +
geom_jitter(alpha = 0.3, size = 0.5) +
theme_bw() +
theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
labs(x = "Variables", y = "Valores") +
scale_color_brewer(palette = "Set1", name = "Probabilidad de Infarto", labels = c('0 - Menor Probabilidad', '1 - Mayor Probabilidad')) +
ggtitle("Gráfico de Cajas con Puntos - Variables Numéricas y Outliers")
Observaciones Podemos ver como hay puntos muy alejados
de las medias y de los boxplots creados en las variables chol, thalachh
y trtbps, por lo que, vamos a estudiar si mediante una función creada
según las desviaciones estandard, se eliminan estos valores y dejamos el
conjunto de datos sin potenciales valores outliers.
Para limpiar los outliers usamos un enfoque de desviaciones estándar (SD), el cual usa la distribución normal de los datos.
# Creamos un dataframe de las variables de las cuales hemos de quitar outliers, excluyendo age y oldpeak
df_outliers<-as.data.frame(heart %>%
select("trtbps","thalachh","chol"))
# Función para quitar outliers
remove_outliers_sd <- function(df_outliers, threshold = 5) {
# Loop a través de cada columna numérica del dataframe
for (col in names(df_outliers)) {
if(is.numeric(df_outliers[[col]])) {
col_mean <- mean(df_outliers[[col]], na.rm = TRUE)
col_sd <- sd(df_outliers[[col]], na.rm = TRUE)
df_outliers <- df_outliers[abs((df_outliers[[col]] - col_mean) / col_sd) <= threshold, ]
}
}
df_outliers
}
heart_clean <-remove_outliers_sd(heart,c("trtbps" ,"thalachh", "chol"))
## Warning in abs((df_outliers[[col]] - col_mean)/col_sd) <= threshold: longer
## object length is not a multiple of shorter object length
## Warning in abs((df_outliers[[col]] - col_mean)/col_sd) <= threshold: longer
## object length is not a multiple of shorter object length
## Warning in abs((df_outliers[[col]] - col_mean)/col_sd) <= threshold: longer
## object length is not a multiple of shorter object length
## Warning in abs((df_outliers[[col]] - col_mean)/col_sd) <= threshold: longer
## object length is not a multiple of shorter object length
## Warning in abs((df_outliers[[col]] - col_mean)/col_sd) <= threshold: longer
## object length is not a multiple of shorter object length
# Observamos el cambio de las dimensiones
dim(heart_clean)
## [1] 302 14
Los valores potenciales outliers no han sido eliminados debido que pueden ser posibles valores de las variables, con lo que, tenemos el conjunto de datos limpio y nos hemos asegurado de que no hay ningún valor que se aleje de la realidad.
(p.ej., si se van a comparar grupos de datos, ¿cuáles son estos grupos y qué tipo de análisis se van a aplicar?)
Para analizar y comparar los datos seleccionados, dividiremos el enfoque en tres partes, centrándonos en la predicción de ataques cardíacos (variable “output”) en relación con las variables de interés. Dividiremos el análisis en tres partes sobre las variables que anteriormente hemos seleccionado. El objetivo y la respuesta a contestar es el tratar de aclarar que tipo de condiciones ayudan a predecir con mejor medida un ataque al corazón.
Los análisis que realizaremos son los siguientes
Matriz de Correlaciones: Exploraremos las relaciones lineales entre todas las variables seleccionadas. Este análisis nos mostrará cómo se correlacionan entre sí las variables, permitiendo identificar asociaciones y patrones de relación, lo que podría sugerir qué variables están más estrechamente relacionadas con la presencia de ataques cardíacos.
ANOVA (Análisis Comparativo): Evaluaremos la diferencia en la variable de salida (“output”) en función de todas las variables incluidas también en la matriz de correlación. Esto nos permite determinar si hay diferencias significativas en la media de “output” entre los distintos niveles de estas variables.
Modelo Predictivo (Regresión Logística): Utilizaremos una regresión logística para predecir la ocurrencia de ataques cardíacos (“output”) basándonos en las variables con una correlación relevante en la matriz anterior. Analizaremos variables como el tipo de dolor torácico, frecuencia cardíaca máxima alcanzada, tasa de mortalidad, angina inducida por el ejercicio, pendiente del segmento ST máximo del ejercicio y el número de grandes buques. El objetivo es comprender qué variables son predictivas de ataques cardíacos y en qué medida influyen en la predicción.
Estos análisis proporcionarán una visión detallada sobre cómo las diferentes variables están relacionadas con la presencia de ataques cardíacos y qué factores pueden ser más relevantes para predecirlos.
Para evaluar la normalidad de las variables seleccionadas, empleamos la prueba de Spahiro-Wilk
# Una vez tenemos los datos discretizados, comprobamos la normalidad
# Usamos la prueba de Shapiro-Wilk para verificar la normalidad de cada variable numérica
variables <- c("age", "trtbps", "chol", "thalachh", "oldpeak")
resultados_shapiro <- lapply(heart_clean[variables], shapiro.test)
names(resultados_shapiro) <- variables
# Verificar la estructura de las variables seleccionadas en el conjunto de datos 'heart'
str(heart_clean[, variables])
## tibble [302 × 5] (S3: tbl_df/tbl/data.frame)
## $ age : num [1:302] 63 37 41 56 57 57 56 44 52 57 ...
## $ trtbps : num [1:302] 145 130 130 120 120 140 140 120 172 150 ...
## $ chol : num [1:302] 233 250 204 236 354 192 294 263 199 168 ...
## $ thalachh: num [1:302] 150 187 172 178 163 148 153 173 162 174 ...
## $ oldpeak : num [1:302] 2.3 3.5 1.4 0.8 0.6 0.4 1.3 0 0.5 1.6 ...
# Mostramos los resultados
print(resultados_shapiro)
## $age
##
## Shapiro-Wilk normality test
##
## data: X[[i]]
## W = 0.98664, p-value = 0.006745
##
##
## $trtbps
##
## Shapiro-Wilk normality test
##
## data: X[[i]]
## W = 0.96573, p-value = 1.419e-06
##
##
## $chol
##
## Shapiro-Wilk normality test
##
## data: X[[i]]
## W = 0.94658, p-value = 5.196e-09
##
##
## $thalachh
##
## Shapiro-Wilk normality test
##
## data: X[[i]]
## W = 0.97679, p-value = 8.268e-05
##
##
## $oldpeak
##
## Shapiro-Wilk normality test
##
## data: X[[i]]
## W = 0.84522, p-value < 2.2e-16
Los resultados de la normalidad muestran que para la variable ‘age’ (edad) hay evidencia suficiente para rechazar la hipótesis nula y afirmar que los datos no siguen una distribución normal, igual que la variable ‘trtbps’ (presión arterial en reposo) y la variable ‘oldpeak’, donde la evidencia para rechazar la hipótesis de normalidad es más fuerte.
Por otro lado, ni la variable ‘chol’ (colesterol) ni la variable ‘thalachh’ (ritmo cardíaco máximo aclanzada) muestran suficiente evidencia para rechazar la hipótesis nula de normalidad, sugiriendo que los datos de ambas variables podrían seguir una distribución normal.
Calculamos las varianzas de las variables numéricas agrupadas por categorías de edad. Esto nos va a proporcionar una visión de como varían ‘age’, ‘trtbps’, ‘chol’, ‘thalachh’, y ‘oldpeak’ en distintos grupos de edad en el riesgo de sufrir un ataque cardíaco.
Clasificamos la varible ‘output’ en dos categorías (‘Yes’ y ’No) para investigar las varianzas de las variables numéricas respecto a la probabilidad de sufrir un ataque cardíaco
Los resultados resaltan las diferencias en las varianzas de estas variables entre aquellos casos con mayor probabilidad de sufrir un ataque cardíaco y los que no.
Esta evaluación proporciona una visión detallada de cómo las variables numéricas varían en relación con la edad y la probabilidad de sufrir un ataque cardíaco, lo que puede ser fundamental para comprender los factores de riesgo asociados
Para realizar un análisis comparativo de todas las variables numéricas y la variable output, empleamos la prueba estadística de ANOVA, prueba que evalúa si hay diferencias significativas en la media de la variable de salida entre los distintos niveles de las variables numéricas.
Parece que la frecuencia cardíaca máxima alcanzada (thalachh), el número de grandes vasos (caa), el tipo de dolor de pecho (cp), la presencia de angina inducida por el ejercicio (exng) y, en menor medida, el tipo de pendiente del segmento ST del electrocardiograma en reposo (slp), la tasa de mortalidad (thall) y la depresión inducida por el ejercicio (oldpeak), muestran asociaciones significativas con la presencia de enfermedades cardíacas. Estos hallazgos, indicados por los valores de p altamente significativos , podrían sugerir la importancia de estas variables en la predicción o diagnóstico de enfermedades cardíacas en el conjunto de datos analizado.
Por otro lado, variables como la edad (age), el sexo (sex), el nivel de azúcar en sangre en ayunas (fbs), el resultado del electrocardiograma en reposo (restecg), la presión arterial en reposo (trtbps) y el colesterol (chol) no parecen demostrar una asociación significativa con la variable de salida (output) en este análisis, ya que sus valores p no alcanzan niveles de significancia estadística.
Estos resultados proporcionan una visión inicial sobre qué variables podrían ser más relevantes al abordar problemas relacionados con enfermedades cardíacas en este contexto específico. Sin embargo, es importante tener en cuenta que estos hallazgos pueden requerir una validación adicional o un análisis más detallado para confirmar su relevancia clínica o predictiva, como lo haremos a continuación mediante un modelo de regresión logística
Para construir un modelo predictivo usando regresión logística con las variables seleccionadas del ANOVA anterior, usamos la función glm().
El modelo de regresión logística tiene como objetivo predecir la probabilidad de ocurrencia de enfermedades cardíacas (output) a partir de un conjunto de variables predictoras (cp, thalachh, thall, oldpeak, exng, slp y caa).
En resumen, las variables “cp” (Tipo de dolor torácico) y “thall” (Tasa de mortalidad) parecen ser las más influyentes para predecir la ocurrencia de enfermedades cardíacas en este modelo. Otras variables como “slp”, “caa”, “thalachh” y “exng” muestran asociaciones que podrían ser relevantes a diferentes niveles de confianza o podrían necesitar más datos para una conclusión más sólida.
El AIC del modelo es 58.647, lo que sugiere que este modelo podría mejorar con ajustes adicionales o la inclusión de más variables predictoras. La deviance residual es significativamente menor que la deviance nula, indicando que las variables incluidas en el modelo explican parte de la variabilidad en la presencia de enfermedades cardíacas.
Los hallazgos de este análisis proporcionan claridad sobre las variables más relevantes para predecir la ocurrencia de enfermedades cardíacas.
El tipo de dolor torácico (cp) y la tasa de mortalidad (thall) emergen como indicadores significativos de enfermedades cardíacas, mostrando asociaciones claras con la presencia de esta condición en el análisis de regresión logística. Además, la frecuencia cardíaca máxima alcanzada (thalachh) y el número de grandes vasos (caa) también muestran vínculos potenciales, aunque su confirmación estadística podría requerir más datos.
La angina inducida por el ejercicio (exng) y la pendiente del segmento ST máximo del ejercicio (slp) no presentan asociaciones estadísticamente significativas con la presencia de enfermedades cardíacas según este análisis.
La depresión inducida por el ejercicio (oldpeak), aunque no muestra asociación significativa, no parece influir en la probabilidad de ocurrencia de enfermedades cardíacas en este modelo.
Estos resultados subrayan la importancia del dolor torácico y la tasa de mortalidad como predictores potenciales de enfermedades cardíacas. Sin embargo, se destaca la necesidad de mayor validación para algunas variables y la posibilidad de ajustes adicionales en el modelo, ya que algunos factores podrían tener influencias más sutiles o necesitar mayor evidencia para confirmar su contribución a la predicción de esta condición médica.